import exp from "express"
import bc from "bcryptjs"
import p from "../prisma/validation.js"
import jwt from "jsonwebtoken"
import "dotenv/config"
import { z, ZodError } from "zod"
import check_token from "../middleware/check_token.js"
import { getErrorMessages } from "../util.js"




const router = exp.Router()


router.post("/auth/login", async (req, res) => {
    const email = req.body.email
    const password = req.body.password
    try {
        const user = await p.user.findUnique({
            where: { email }
        })
        if (user && bc.compareSync(password, user.password)) {
            const token = jwt.sign({
                id: user.id,
                exp: Math.ceil((Date.now() / 1000)) + 7 * 24 * 60 * 60 // 7 天后过期
            }, process.env.SECRET)
            await p.user.update({
                where: { id: user.id },
                data: {
                    token
                }
            })
            res.json({
                msg: "Success",
                token,
                // iat: jwt.verify(token,process.env.SECRET).iat,
                // exp: Math.ceil(jwt.verify(token,process.env.SECRET).exp),
                user: {
                    id: parseInt(user.id),
                    name: user.name,
                    email: user.email
                }
            })
        }
        else {
            res.status(401).json({
                msg: "Unauthorized"
            })
        }
    }
    catch (e) {
        //console.log(e);

        res.status(401).json({
            msg: "Unauthorized"
        })
    }


})

router.get("/auth/logout", async (req, res) => {
    try {
        const [key, token] = req.headers["authorization"].split(" ")
        if (key === "Bearer" && token) {
            let info = jwt.verify(token, process.env.SECRET)
            const user = await p.user.update({
                where: { id: info.id },
                data: { token: null }
            })
        }
        res.status(200).json({
            msg: "Succcess"
        })

    }
    catch (e) {
        res.status(401).json({
            msg: "Unauthorized"
        })
    }
})

router.get("/departments", check_token, async (req, res) => {
    res.status(200).json({
        msg: "Success",
        data: await p.department.findMany({
            include: {
                clubs: req.query._embed && req.query._embed.toLowerCase() === "clubs"
            }
        })
    })

})

router.get("/departments/:id", check_token, async (req, res) => {
    res.status(200).json({
        msg: "Success",
        data: await p.department.findMany({
            where: { id: parseInt(req.params.id) },
            include: {
                clubs: req.query._embed && req.query._embed.toLowerCase() === "clubs"
            }
        })
    })

})

router.get("/clubs", async (req, res) => {
    const clubs = await p.club.findMany({
        select: {
            id: true,
            name: true,
            capacity: true,
            department: {
                select: {
                    name: true
                }
            }
        }
    })
    let _clubs = await Promise.all(clubs.map(async (club) => {
        club.department = club.department.name
        const count = await p.memberOnClub.count({
            where: {
                clubId: club.id
            }
        })
        club.availableCapacity = club.capacity - count
        return club
    }))
    res.status(200).json({
        msg: "Success",
        data: _clubs
    })
})

router.post("/departments", async (req, res) => {
    try {
        await p.department.create({
            data: req.body
        })

        res.status(200).json({
            msg: "Success"
        })
    }
    catch (e) {
        console.log(e);
        let errors = {}
  
        if(e instanceof ZodError) errors = getErrorMessages(e.format())

        if (Object.keys(errors).length > 0) {
            res.status(422).json({
                msg: "Data cannot be processed",
                errors

            })
            return
        }

        res.status(422).json({
            msg: "Data cannot be processed",
        })
    }
})

router.delete("/departments/:id", async (req, res) => {
    try {
        await p.department.delete({
            where: { id: parseInt(req.params.id) }
        })
        res.json({
            msg: "Success"
        })
    }
    catch (e) {
        if (e.meta.cause.includes("does not exist")) {
            res.status(404).json({
                msg: "Not found"
            })
            return
        }
        res.json(e)
    }

})

router.patch("/departments/:id", async (req, res) => {
    const v = z.object({
        name: z.string({
            required_error: "Name must be provided!",
            invalid_type_error: "Name must be a string!"
        }).min(2, "Name must be at least 2 characters!"),
        email: z.string().email()
    }).partial()

    try {
        v.parse(req.body)
        await p.department.update({
            where: { id: parseInt(req.params.id) },
            data: req.body
        })
        res.status(200).json({
            msg: "Success"
        })
    }
    catch (e) {
        res.json(e)
    }
})

router.put("/members/:id/move-in/clubs", async (req, res) => {
    const v = z.object({
        id: z.coerce.number().int().positive(),
        clubs: z.number().int().array().nonempty()
    })
    req.body.id = req.params.id
    const result = v.safeParse(req.body)
       
    if(!result.success){
        console.log(result.error.format());
        
        res.status(422).json({
            msg: "Data cannot be processed!",
            errors: result.error.format()
        })
        return
    }
    try {
        await Promise.all(req.body.clubs.map(async c => {
            const count = await p.memberOnClub.count({
                where: {
                    memberId: parseInt(req.params.id),
                    clubId: c
                }
            })
            console.log("Count: ",count);
            
            if (count===0){
                await p.memberOnClub.create({
                    data: {
                        memberId: parseInt(req.params.id),
                        clubId: c,
                        joinDate: (new Date()).toISOString()
                    }
                })
            }
        }));
        res.status(200).json({
            msg: "Success"
        })

    }
    catch(e){
        console.log(e);
        
        res.json({
            msg: "Data cannot be processed!"
        })
    }

   
})

router.put("/members/:id/move-out/clubs", async (req,res)=>{
    try{
        await Promise.all(req.body.clubs.map(async (c)=>{
            const cnt = await p.memberOnClub.count({
                where: {
                    memberId: parseInt(req.params.id),
                    clubId: c
                }
            })
            if(cnt>0){
                await p.memberOnClub.delete({
                    where: {
                        memberId_clubId: {
                            memberId: parseInt(req.params.id),
                            clubId: c
                        }
                        
                    }
                })
            }
     
            
        }))
        res.json({
            msg: "Success"
        })
    }
    catch(e){
        console.log(e);
        res.json({
            msg: "Operation failed"
        })

    }
})




router.post("/test", async (req, res) => {
    try {
        await p.department.createMany({
            data: req.body.departments
        })
    }
    catch(e){
        console.log(e);
        let errors = {}
  
        if(e instanceof ZodError) errors = getErrorMessages(e.format())

        if (Object.keys(errors).length > 0) {
            res.status(422).json({
                msg: "Data cannot be processed",
                errors

            })
            return
        }

        res.status(422).json({
            msg: "Data cannot be processed",
        })
    }
})

export default router

